package main

import (
	"errors"
	"fmt"
)

// 函数声明，格式如下：
//
//	func funcName(params) result  {
//		body
//	}
func sum(a int, b int) int {
	fmt.Println("******函数声明******")
	return a + b
}

// 函数多值返回
func sum2(a, b int) (int, error) {
	fmt.Println("******函数多值返回******")
	if a < 0 || b < 0 {
		return 0, errors.New("a或者b不能是负数")
	}
	return a + b, nil
}

// 可变参数
func sum3(params ...int) int {
	fmt.Println("******可变参数******")
	sum := 0
	for _, i := range params {
		sum += i
	}
	return sum
}

//包级函数
//同一个包中的函数哪怕是私有的（函数名称首字母小写）也可以被调用。如果不同包的函数要被调用，那么函数的作用域必须是公有的，也就是函数名称的首字母要大写，比如 Println。
//函数名称首字母小写代表私有函数，只有在同一个包中才可以被调用；
//函数名称首字母大写代表公有函数，不同的包也可以调用；
//任何一个函数都会从属于一个包。

// 闭包
// 有了匿名函数，就可以在函数中再定义函数（函数嵌套），定义的这个匿名函数，也可以称为内部函数。更重要的是，在函数内定义的内部函数，可以使用外部函数的变量等，这种方式也称为闭包。
// 在go语言中，函数也是一种类型，它也可以被用来声明函数类型的变量、参数或者作为另一个函数的返回值类型。
func colsure() func() int {
	i := 0
	return func() int {
		i++
		return i
	}
}

// 方法
type Age uint

func (age Age) String() {
	fmt.Println("the age is ", age)
}
func (age *Age) Modify() {
	*age = Age(30)
}

func main() {
	result := sum(1, 2)
	fmt.Println(result)

	result2, err2 := sum2(10, 20)
	if err2 != nil {
		fmt.Println(err2)
	} else {
		fmt.Println(result2)
	}

	fmt.Println(sum3(1, 2))
	fmt.Println(sum3(1, 2, 3))
	fmt.Println(sum3(1, 2, 3, 4))

	//匿名函数
	sum2 := func(a, b int) int {
		return a + b
	}
	fmt.Println("匿名函数和闭包：", sum2(1, 2))

	//闭包
	cl := colsure()
	fmt.Println("闭包：", cl())
	fmt.Println("闭包：", cl())

	//方法调用
	//不管是使用值类型接收者，还是指针类型接收者，要先确定你的需求：在对类型进行操作的时候是要改变当前接收者的值，还是要创建一个新值进行返回？这些就可以决定使用哪种接收者。
	age := Age(25)
	age.String()
	age.Modify()
	age.String()
}
